package com.wumai.modernguilib.panel;

import com.mojang.blaze3d.matrix.MatrixStack;
import com.wumai.modernguilib.component.BaseComponent;

import java.util.ArrayList;
import java.util.List;

public abstract class BaseView extends BaseComponent {
    protected List<BaseComponent> children = new ArrayList<>();

    public BaseView() {
        super();
    }

    public BaseView(int x, int y, int width, int height) {
        super(x, y, width, height);
    }

    protected final void renderChildren(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) {
        // 渲染子组件
        for (BaseComponent child : children) {
            if (child.isVisible()) {
                child.render(matrixStack, mouseX, mouseY, partialTicks);
            }
        }
    }

    // 这里更新布局仅仅是设置其子组件的布局，因为子组件的位置大小由父组件管理
    public abstract void updateLayout();

    protected abstract void renderBackground(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks);

    protected abstract void renderContent(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks);

    @Override
    public void onParentLayoutChanged() {
        // 默认实现为空，子类可以重写
        super.onParentLayoutChanged();          // 其实这里是在父组件更新布局之后，自己的布局被更新了，调用这个方法是更新自己的布局，也就是这一级的子组件
        for (BaseComponent child : children) {
            child.onParentLayoutChanged();      // 递归地调用子组件的布局进行更新
        }
    }

    public void addChild(BaseComponent component) {
        component.setParent(this);
        children.add(component);
        updateLayout();
        component.onParentLayoutChanged();
        onChildAdded(component);
    }

    public void removeChild(BaseComponent component) {
        children.remove(component);
        component.setParent(null);
        updateLayout();
        onChildRemoved(component);
    }

    // 当子组件被添加时调用，子类可以重写此方法进行布局更新之后的操作
    protected void onChildAdded(BaseComponent component) {
        // 默认实现为空，子类可以重写
    }

    // 当子组件被移除时调用，子类可以重写此方法进行布局更新
    protected void onChildRemoved(BaseComponent component) {
        // 默认实现为空，子类可以重写
    }

    public List<BaseComponent> getChildren() {
        return children;
    }

    public float[] getPadding() {
        return paddings;
    }

    /**
     * 鼠标点击事件处理方法，将事件传递给子组件
     * @param mouseX 鼠标X坐标(NDC)
     * @param mouseY 鼠标Y坐标(NDC)
     * @param button 鼠标按键
     * @return 是否处理了该事件
     */
    // 带有子组件的组件就有限判断子组件是否符合条件，符合条件直接返回，不用判断当前组件
    @Override
    public boolean mouseClicked(double mouseX, double mouseY, int button) {
        if (!visible || !enabled)
            return false;

        // 将事件传递给子组件
        // 先看子组件是否能处理
        // 这里其实就是深度优先搜索
        for (BaseComponent child : children) {
            if (child.mouseClicked(mouseX, mouseY, button)) {
                return true;
            }
        }

        // 再看自身能否处理
        return super.mouseClicked(mouseX, mouseY, button);
    }

    /**
     * 鼠标释放事件处理方法，将事件传递给子组件
     * @param mouseX 鼠标X坐标(NDC)
     * @param mouseY 鼠标Y坐标(NDC)
     * @param button 鼠标按键
     * @return 是否处理了该事件
     */
    @Override
    public boolean mouseReleased(double mouseX, double mouseY, int button) {
        if (!visible || !enabled)
            return false;
        // 将事件传递给子组件
        for (BaseComponent child : children) {
            if (child.mouseReleased(mouseX, mouseY, button)) {
                return true;
            }
        }
        return super.mouseReleased(mouseX, mouseY, button);
    }

    @Override
    public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) {
        if (!visible || !enabled)
            return false;

        // 将事件传递给子组件
        for (BaseComponent child : children) {
            if (child.mouseDragged(mouseX, mouseY, button, dragX, dragY)) {
                return true;
            }
        }

        return super.mouseDragged(mouseX, mouseY, button, dragX, dragY);
    }

    @Override
    public boolean mouseScrolled(double mouseX, double mouseY, double delta) {
        if (!visible || !enabled)
            return false;

        // 将事件传递给子组件
        for (BaseComponent child : children) {
            if (child.mouseScrolled(mouseX, mouseY, delta)) {
                return true;
            }
        }

        return super.mouseScrolled(mouseX, mouseY, delta);
    }
}